package com.starnet.yarnmonitor.yarn.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;


import com.starnet.yarnmonitor.security.utils.UserUtil;
import com.starnet.yarnmonitor.yarn.entity.UpgradeJar;
import com.starnet.yarnmonitor.yarn.handler.ApiException;
import com.starnet.yarnmonitor.yarn.mapper.UpgradeJarMapper;
import com.starnet.yarnmonitor.yarn.service.UpgradeJarService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.starnet.yarnmonitor.yarn.utils.HttpUtils;
import com.starnet.yarnmonitor.yarn.utils.LinuxUtils;
import com.starnet.yarnmonitor.yarn.utils.MD5Utils;
import com.starnet.yarnmonitor.yarn.vo.result.Result;
import lombok.extern.log4j.Log4j;
import okhttp3.*;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.UUID;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 陈佳豪
 * @since 2022-06-01
 */
@Log4j
@Service
public class UpgradeJarServiceImpl extends ServiceImpl<UpgradeJarMapper, UpgradeJar> implements UpgradeJarService {
    @Autowired
    UpgradeJarMapper upgradeJarMapper;
    @Autowired
    LinuxUtils linuxUtils;
    @Autowired
    Environment environment;

    @Override
    public boolean uploadUpgradeJar(MultipartFile multipartFile) throws IOException {
        //临时文件夹路径
        String uid = String.valueOf(UUID.randomUUID());
        File checkDir = new File("//check_tmp//" + multipartFile.getOriginalFilename() + "_" + uid);
//        System.out.println(checkDir.getCanonicalPath());
        //创建校验临时文件夹 no problem
        checkDir.mkdirs();
        //把上传的文件包放进去
        try (InputStream is = multipartFile.getInputStream();
             FileOutputStream os = new FileOutputStream("//check_tmp//" + multipartFile.getOriginalFilename() + "_" + uid + "//" + multipartFile.getOriginalFilename())) {
            byte[] buffer = new byte[1024 * 1024];
            int length;
            while ((length = is.read(buffer)) != -1) {
                os.write(buffer, 0, length);
            }
        }
        String source = "//check_tmp//" + multipartFile.getOriginalFilename() + "_" + uid + "//" + multipartFile.getOriginalFilename();
        String dest = "//check_tmp//" + multipartFile.getOriginalFilename() + "_" + uid + "//";
        String shell = linuxUtils.shell("tail -n +3 " + source + " > /check_tmp/" + multipartFile.getOriginalFilename() + "_" + uid + "/checkMD5.tar.gz");
        //待检验主体文件
        File checkFile = new File("//check_tmp//" + multipartFile.getOriginalFilename() + "_" + uid + "//checkMD5.tar.gz");
        String md5 = MD5Utils.getMD5(checkFile);
        //获取文件的md5
        String presetMD5 = linuxUtils.shell("head -n +1 " + "/check_tmp/" + multipartFile.getOriginalFilename() + "_" + uid + "/" + multipartFile.getOriginalFilename());
        //把没用的后面mysh.tar.gz去掉
        presetMD5 = presetMD5.substring(0, presetMD5.indexOf(' '));
        //获取第二行版本号
        String version = linuxUtils.shell("sed -n '2,2p' " + "/check_tmp/" + multipartFile.getOriginalFilename() + "_" + uid + "/" + multipartFile.getOriginalFilename());
        linuxUtils.shell("");
        System.out.println("md5:" + md5);
        System.out.println("presetMD5:" + presetMD5);
        System.out.println("version:" + version);
        if (!md5.equals(presetMD5)) {
            System.out.println(presetMD5);
            System.out.println(md5);
            System.out.println(presetMD5.length());
            System.out.println(md5.length());
            FileUtils.deleteDirectory(checkDir);
            log.error("用户" + UserUtil.getCurrentUserId() + "上传了一个非法升级包，已退回");
            throw new ApiException("检测到非法升级包，已退回");
        }
        version = version.trim();
        File upgradeDir = new File("//upgrade//" + version);
        synchronized (UpgradeJar.class) {
            //查看是否已经已经存在该版本号的文件
            //通过 建立版本号文件夹
            //如果该版本号文件已存在linux   数据库和文件系统中
            LambdaQueryWrapper<UpgradeJar> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UpgradeJar::getVersion, version);
            UpgradeJar jarInDB = upgradeJarMapper.selectOne(queryWrapper);
            boolean isExistInDB = !(jarInDB == null);
            if (upgradeDir.exists() || isExistInDB) {
                //删除当前临时文件 并抛异常
                FileUtils.deleteDirectory(checkDir);
                log.error("用户" + UserUtil.getCurrentUserId() + "上传了一个已存在的安装包");
                throw new ApiException("linux中存在此升级包");
            }
            //如果不存在,解压到目的地文件夹:先创建文件夹->后解压->写入数据库
            upgradeDir.mkdirs();
            linuxUtils.shell("tar -zxvf " + "/check_tmp/" + multipartFile.getOriginalFilename() + "_" + uid + "/checkMD5.tar.gz -C /upgrade/" + version);
            UpgradeJar upgradeJar = new UpgradeJar(null, "/upgrade/" + version + "/mysh/" + "upgrade.sh", Timestamp.valueOf(LocalDateTime.now()), version);
            upgradeJarMapper.insert(upgradeJar);
            FileUtils.deleteDirectory(checkDir);
        }
        log.info("用户" + UserUtil.getCurrentUserId() + "新增了升级包，版本：" + version);
        return true;
    }

    @Override
    public boolean upgradeById(Integer id) throws IOException {
        //查看数据库中有没有此升级包
        UpgradeJar upgradeJar = upgradeJarMapper.selectById(id);
        if (upgradeJar == null) {
            throw new ApiException("不存在该升级包");
        }
        //比较升级的版本是不是高级于当前版本
        String curVersion = environment.getProperty("version").trim();
        String toVersion = upgradeJar.getVersion().trim();
        boolean legalUpgrade = compareVersion(curVersion, toVersion);
        if (!legalUpgrade) {
            log.error("用户升级版本 " + curVersion + " -> " + toVersion + " 错误");
            throw new ApiException("只能升级更高版本");
        }
        String shellPath = upgradeJar.getFileName();
        OkHttpClient client = new OkHttpClient().newBuilder()
                .build();
        MediaType mediaType = MediaType.parse("text/plain");
        Request request = new Request.Builder()
                .url("http://localhost:8081/upgrade?shellPath="+shellPath+" "+toVersion)
                .method("GET", null)
                .build();
       client.newCall(request).execute();

        return true;
    }

    public static boolean compareVersion(String curVersion, String toVersion) {
        // 2.4.5.6.5
        // 1.2.3.4.5
        String[] digit1 = toVersion.split("\\.");
        String[] digit2 = curVersion.split("\\.");
        if (digit1.length != digit2.length) {
            return false;
        }
        for (int i = 0; i < digit1.length; i++) {
            if (Integer.valueOf(digit1[i]) > Integer.valueOf(digit2[i])) {
                return true;
            }
            if (Integer.valueOf(digit1[i]) < Integer.valueOf(digit2[i])) {
                return false;
            }
        }
        return false;

    }
}
